/*
 * hashtable.c
 * 
 * Tiedosto sisältää hashtable<string,json_item> rakenteen, ja sitä käytetään
 * tiedostoa luettaessa.
 * 
 * author: ossi
 * 
 */
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <wchar.h>
#include "hashtable.h"
#include "dynarray.h"
#include "jsonparser.h"

//Ossi teki kaiken

json_item* ht_get(hashtable* ht, wchar_t* key);

/*
 * Palauttaa uuden hashtablen
 */
hashtable* ht_new() {
    hashtable* tmp = malloc(sizeof (hashtable));
    if (tmp == NULL) {
        return NULL;
    }

    tmp->array = da_new();

    if (tmp->array == NULL) {
        return NULL;
    }

    for (unsigned int i = 0; i < 100; ++i) {
        da_append(tmp->array, NULL);
    }
    return tmp;
}

/*
 * Palauttaa avaimen hash-arvon
 */
unsigned int ht_hash(const wchar_t* str) {
    unsigned long hash = 5381;
    int c;

    while ((c = *str++))
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    unsigned int final_hash = (unsigned int) (hash % 100);
    return final_hash;
}

/*
 *Palauttaa uuden ht_itemin avaimella key
 */
ht_item* ht_new_item(wchar_t* key) {
    ht_item* tmp = malloc(sizeof (ht_item));

    if (tmp == NULL) return NULL;

    tmp->key = key; // mallocoitu jsonparserissa
    return tmp;
}

/*
 * Lisää hashtauluun kuvauksen key->data
 */
bool ht_put(hashtable* ht, wchar_t* key, json_item* data) {
    if (ht == NULL || key == NULL) return false;
    if (ht_get(ht, key) != NULL) return false;

    ht_item* tmp = ht_new_item(key);
    if (tmp == NULL) return false;



    tmp->data = data;

    unsigned int index = ht_hash(key);
    ht_item* next = (ht_item*) da_get(ht->array, index);

    tmp->next = next;

    da_set(ht->array, index, tmp);

    return true;
}

/*
 * Palauttaa avaimeen key assosioidun arvon
 */
json_item* ht_get(hashtable* ht, wchar_t* key) {
    unsigned int hash = ht_hash(key);
    ht_item* item = (ht_item*) da_get(ht->array, hash);

    while (item != NULL) { //seurataan ylivuotolistaa
        if (wcscmp(key, item->key) == 0) return item->data;
        item = item->next;
    }
    return NULL;
}

/*
 * vapauttaa ht_itemin sisältämän tiedon kutsumalla oikeaa funktiota
 */
void ht_free_item(ht_item* hi) {
    while (hi != NULL) {
        json_item* ji = hi->data;
        json_item_free(ji);
        
        ht_item* tmp = hi;
        
        hi = hi->next;
        
        free(tmp->key);
        free(tmp);
    }
}
/*
 * Vapauttaa hashtaulun
 */
void ht_free(hashtable* ht) {
    for (unsigned int i = 0; i < 100; ++i) {
        ht_item* tmp = (ht_item*) da_get(ht->array, i);
        if (tmp != NULL) {
            ht_free_item(tmp);
        }
    }
    da_free(ht->array);
    free(ht);
}
